package cn.wm.server;

import cn.hutool.log.Log;
import cn.hutool.log.StaticLog;
import cn.wm.constant.MessageType;
import cn.wm.constant.ResultType;
import cn.wm.struct.Message;
import cn.wm.struct.MessageHeader;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * LoginAuthRespHandler
 *
 * @author wm
 * @version 1.0
 * 2021/6/25 10:47
 **/
public class LoginAuthRespHandler extends SimpleChannelInboundHandler<Message> {

    private static final Log log = StaticLog.get();
    /**
     * 考虑到安全，链路的建立需要通过基于IP地址或者号段的黑白名单安全认证机制，本例中，多个IP通过逗号隔开
     */
    private Map<String, Boolean> nodeCheck = new ConcurrentHashMap<String, Boolean>();
    private String[] whitekList = {"127.0.0.1", "192.168.56.1"};

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Message message) throws Exception {
        if (message.getHeader() != null && message.getHeader().getType() == MessageType.LOGIN_REQ.value()) {
            String nodeIndex = ctx.channel().remoteAddress().toString();
            Message loginResp = null;
            // 重复登陆，拒绝
            if (nodeCheck.containsKey(nodeIndex)) {
                log.info("重复登录,拒绝请求!");
                loginResp = buildResponse(ResultType.FAIL);
            } else {
                InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
                String ip = address.getAddress().getHostAddress();
                boolean isOK = false;
                for (String WIP : whitekList) {
                    if (WIP.equals(ip)) {
                        isOK = true;
                        break;
                    }
                }
                loginResp = isOK ? buildResponse(ResultType.SUCCESS) : buildResponse(ResultType.FAIL);
                if (isOK)
                    nodeCheck.put(nodeIndex, true);
            }
            log.info("The login response is : {} body [{}]", loginResp, loginResp.getBody());
            ctx.writeAndFlush(loginResp);
        } else {
            ctx.fireChannelRead(message);
        }
    }

    /**
     * 服务端接到客户端的握手请求消息后，如果IP校验通过，返回握手成功应答消息给客户端，应用层成功建立链路，否则返回验证失败信息。消息格式如下：
     * 1.消息头的type为4
     * 2.可选附件个数为0
     * 3.消息体为byte类型的结果，0表示认证成功，1表示认证失败
     *
     * @param result
     * @return
     */
    private Message buildResponse(ResultType result) {
        Message message = new Message();
        MessageHeader header = new MessageHeader();
        header.setType(MessageType.LOGIN_RESP.value());
        message.setHeader(header);
        message.setBody(new byte[]{result.value()});
        return message;
    }

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        nodeCheck.remove(ctx.channel().remoteAddress().toString());// 删除缓存
        ctx.close();
        ctx.fireExceptionCaught(cause);
    }
}
